/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.web.spring.web.bind;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.vacoor.nothing.common.util.StringUtils;
import org.vacoor.nothing.web.domain.Sort;

/**
 * 淘宝形式的排序参数解析器
 * sort=name-asc,age-desc
 * qualifier_sort=e-asc,mm-desc
 *
 * @author vacoor
 */
public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    private static final String DEFAULT_SORT_PARAMETER_NAME = "sort";
    private static final String DEFAULT_PROPERTY_DIRECTION_DELIMITER = "-";
    private static final String DEFAULT_QUALIFIER_DELIMITER = "_";
    private static final Sort.Direction DEFAULT_FALLBACK_DIRECTION = Sort.Direction.ASC;

    private String sortParameterName = DEFAULT_SORT_PARAMETER_NAME;
    private String qualifierDelimiter = DEFAULT_QUALIFIER_DELIMITER;
    private String propertyDirectionDelimiter = DEFAULT_PROPERTY_DIRECTION_DELIMITER;
    private Sort.Direction fallbackDirection = DEFAULT_FALLBACK_DIRECTION;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return Sort.class.equals(parameter.getParameterType());
    }

    @Override
    public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String ordersStr = webRequest.getParameter(getParameterName(sortParameterName, parameter));

        Sort sort = Sort.create();
        if (StringUtils.hasLength(ordersStr)) {
            // name-desc,age-asc
            String[] orders = ordersStr.split(",");
            for (String order : orders) {
                int idx = order.lastIndexOf(propertyDirectionDelimiter);

                Sort.Direction direction = null;
                if (idx > 0 && idx < order.length() - 1) {
                    direction = Sort.Direction.forName(order.substring(idx + 1));
                }
                direction = direction != null ? direction : fallbackDirection;
                String property = idx > 0 ? order.substring(0, idx) : order;

                sort.add(direction, property);
            }
        }
        return sort;
    }

    protected String getParameterName(String source, MethodParameter parameter) {
        StringBuilder segment = new StringBuilder();
        Qualifier qualifier;
        if (parameter != null && (qualifier = parameter.getParameterAnnotation(Qualifier.class)) != null) {
            segment.append(qualifier.value());
            segment.append(qualifierDelimiter);
        }
        segment.append(source);
        return segment.toString();
    }

    public String getSortParameterName() {
        return sortParameterName;
    }

    public void setSortParameterName(String sortParameterName) {
        this.sortParameterName = sortParameterName;
    }

    public String getQualifierDelimiter() {
        return qualifierDelimiter;
    }

    public void setQualifierDelimiter(String qualifierDelimiter) {
        this.qualifierDelimiter = qualifierDelimiter;
    }

    public String getPropertyDirectionDelimiter() {
        return propertyDirectionDelimiter;
    }

    public void setPropertyDirectionDelimiter(String propertyDirectionDelimiter) {
        this.propertyDirectionDelimiter = propertyDirectionDelimiter;
    }

    public Sort.Direction getFallbackDirection() {
        return fallbackDirection;
    }

    public void setFallbackDirection(Sort.Direction fallbackDirection) {
        this.fallbackDirection = fallbackDirection;
    }
}
